home *** CD-ROM | disk | FTP | other *** search
/ CU Amiga Super CD-ROM 17 / CU Amiga Magazine's Super CD-ROM 17 (1997)(EMAP Images)(GB)[!][issue 1997-12].iso / CUCD / Programming / DiceSource / lib / amiga / profile.c < prev    next >
C/C++ Source or Header  |  1997-09-09  |  7KB  |  293 lines

  1.  
  2. /*
  3.  *  PROFILE.C
  4.  *
  5.  *    (c)Copyright 1992-1997 Obvious Implementations Corp.  Redistribution and
  6.  *    use is allowed under the terms of the DICE-LICENSE FILE,
  7.  *    DICE-LICENSE.TXT.
  8.  *
  9.  */
  10.  
  11. #include <exec/types.h>
  12. #include <exec/memory.h>
  13. #include <lib/profile.h>
  14. #include <devices/timer.h>
  15. #include <dos/dos.h>
  16. #include <dos/dosextens.h>
  17. #include <exec/execbase.h>
  18.  
  19. /*
  20.  *  force inline calls under DICE to streamline profiling.  Not required
  21.  *  for prevention of profiling routines getting profiled because this
  22.  *  is handled with __noprof
  23.  */
  24.  
  25. #define  __DICE_INLINE
  26.  
  27. #include <clib/timer_protos.h>
  28. #include <clib/exec_protos.h>
  29. #include <clib/dos_protos.h>
  30. #include <stdio.h>
  31. #include <string.h>
  32.  
  33. typedef struct CommandLineInterface CLI;
  34. typedef struct timerequest Iot;
  35.  
  36. ProfSym *_ProfCache = 0;
  37. ProfSym *_ProfList = 0;
  38. ProfSym *_ProfParent = NULL;
  39. Iot    _ProfIot;
  40. long    _ProfTimeStamp;
  41. short    _ProfId = 1;        /*    id 0 reserved for root    */
  42. short    _Prof2_0;        /*    running under 2.0    */
  43.  
  44. __regargs __noprof void ReadClock13(struct EClockVal *);
  45.  
  46. __regargs __noprof void
  47. _CProfInit(ps, sysbase)
  48. ProfSym *ps;
  49. struct ExecBase *sysbase;
  50. {
  51.     ps->ps_Link = _ProfList;
  52.     ps->ps_Id = _ProfId++;
  53.     _ProfList = ps;
  54.  
  55.     if (sysbase->LibNode.lib_Version >= 36)
  56.     _Prof2_0 = 1;
  57. }
  58.  
  59. /*
  60.  *  Profiler call, keeps track of the amount of time a routine takes to
  61.  *  run (separately for each caller of the routine).  Attempts to remove
  62.  *  overhead related to the profiler call itself.
  63.  *
  64.  *  loops and longjumps.  loops are detected when the parent is equal to
  65.  *  the child while longjumps are detected when an element is not equal
  66.  *  to its parent on exit.
  67.  */
  68.  
  69. #define EVSHIFT(ev)  (((ev).ev_hi << 28) | ((unsigned long)(ev).ev_lo >> 4))
  70. #define ECBASE(n)   (n >> 4)
  71.  
  72. /*#define GetEClock(evp) (_Prof2_0 ? (ReadEClock(evp), (evp)->ev_lo = EVSHIFT(*evp)) : ReadClock13(evp))*/
  73. #define GetEClock(evp) if (_Prof2_0) {ReadEClock(evp);(evp)->ev_lo = EVSHIFT(*evp);} else {ReadClock13(evp);}
  74. #define GetEClockBase(evp)  (_Prof2_0 ? ECBASE(ReadEClock(evp)) : 62500)
  75.  
  76. static short InProf;
  77.  
  78. __regargs __noprof void
  79. _CProfExec(id)
  80. void *id;
  81. {
  82.     ProfSym *ps;
  83.     short begMode;
  84.     struct EClockVal ev1;
  85.  
  86.     if (InProf)
  87.     return;
  88.     ++InProf;
  89.  
  90.     GetEClock(&ev1);
  91.  
  92.     /*
  93.      *    find program symbol by Id
  94.      */
  95.  
  96.     begMode = 0;
  97.     {
  98.     ProfSym **pps = &_ProfList;
  99.     short cnt = 0;
  100.  
  101.     for (ps = *pps; ps; ps = *pps) {
  102.         if (id == ps->ps_BegId) {
  103.         begMode = 1;
  104.         break;
  105.         }
  106.         if (id == ps->ps_EndId)
  107.         break;
  108.         pps = &ps->ps_Link;
  109.         ++cnt;
  110.     }
  111.     if (ps && cnt > 8) {        /*    cache    */
  112.         *pps = ps->ps_Link;
  113.         ps->ps_Link = _ProfList;
  114.         _ProfList = ps;
  115.     }
  116.     }
  117.  
  118.     if (begMode) {
  119.     ProfSym *ps2;
  120.  
  121.     /*
  122.      *  begin new entry, close out parent entry then find new entry
  123.      *  point
  124.      */
  125.  
  126.     if (ps2 = _ProfParent)
  127.         ps2->ps_AccumTime += ev1.ev_lo - ps2->ps_TimeStamp;
  128.  
  129.     if (ps->ps_NumCalls == 0) {
  130.         ps->ps_Parent = ps2;
  131.     } else if (ps2 = ps) {
  132.         while (ps->ps_Parent != _ProfParent) {
  133.         if (ps->ps_SibLink) {
  134.             ps = ps->ps_SibLink;
  135.             continue;
  136.         }
  137.         if (ps->ps_SibLink = AllocMem(sizeof(ProfSym), MEMF_PUBLIC|MEMF_CLEAR)) {
  138.             ps = ps->ps_SibLink;
  139.             ps->ps_Size = sizeof(ProfSym);
  140.             ps->ps_Id = _ProfId++;
  141.             ps->ps_Parent = _ProfParent;
  142.             ps->ps_BegId  = ps2->ps_BegId;
  143.             ps->ps_EndId  = ps2->ps_EndId;
  144.             break;
  145.         }
  146.         }
  147.     }
  148.  
  149.     /*
  150.      *  if new entry point found (it had better be!) then set start
  151.      *  point for entry point.
  152.      */
  153.  
  154.     if (ps) {
  155.         ++ps->ps_NumCalls;
  156.         _ProfParent = ps;
  157.         ps->ps_AccumTime = 0;
  158.         GetEClock(&ev1);
  159.         ps->ps_TimeStamp = ev1.ev_lo;
  160.     }
  161.     } else if (ps = _ProfParent) {
  162.     ProfSym *ps2;
  163.  
  164.     /*
  165.      *  close out current entry and restart parent entry
  166.      */
  167.  
  168.     while (ps && ps->ps_EndId != id) {
  169.         ps->ps_AccumTime += ev1.ev_lo - ps->ps_TimeStamp;
  170.         ps->ps_TotalTime += ps->ps_AccumTime;
  171.         if (ps->ps_Parent)
  172.         ps->ps_Parent->ps_AccumTime += ps->ps_AccumTime;
  173.         ps->ps_AccumTime = 0;
  174.         ps = ps->ps_Parent;
  175.     }
  176.     if (ps) {
  177.         ps->ps_AccumTime += ev1.ev_lo - ps->ps_TimeStamp;
  178.         ps->ps_TotalTime += ps->ps_AccumTime;
  179.  
  180.         if (_ProfParent = ps2 = ps->ps_Parent) {
  181.         ps2->ps_AccumTime += ps->ps_AccumTime;
  182.         GetEClock(&ev1);
  183.         ps2->ps_TimeStamp = ev1.ev_lo;
  184.         }
  185.         ps->ps_AccumTime = 0;
  186.     } else {
  187.         _ProfParent = ps;
  188.     }
  189.     }
  190.     --InProf;
  191. }
  192.  
  193. __autoexit __noprof void
  194. _CProfExit()
  195. {
  196.     long fh;
  197.     ProfSym *ps;
  198.     ProfSym *ps2;
  199.     ProfHdr ph;
  200.     struct EClockVal ev1;
  201.     char profBuf[64];
  202.  
  203.     ++InProf;
  204.     profBuf[0] = 'a';
  205.     profBuf[1] = 0;
  206.  
  207.     GetEClock(&ev1);
  208.  
  209.     for (ps = _ProfParent; ps; ps = ps->ps_Parent) {
  210.     ps->ps_AccumTime += ev1.ev_lo - ps->ps_TimeStamp;
  211.     ps->ps_TotalTime += ps->ps_AccumTime;
  212.     if (ps->ps_Parent)
  213.         ps->ps_Parent->ps_AccumTime += ps->ps_AccumTime;
  214.     ps->ps_AccumTime = 0;
  215.     }
  216.  
  217.     {
  218.     CLI *cli = (CLI *)BADDR(((struct Process *)FindTask(NULL))->pr_CLI);
  219.     if (cli) {
  220.         unsigned char *ptr = (char *)BADDR(cli->cli_CommandName);
  221.         short i, j;
  222.         for (i = *ptr; i > 0; --i) {
  223.         if (ptr[i] == ':' || ptr[i] == '/')
  224.             break;
  225.         }
  226.         for (++i, j = 0; i <= *ptr && j < sizeof(profBuf) - 8; ++i, ++j)
  227.         profBuf[j] = ptr[i];
  228.         profBuf[j] = 0;
  229.     }
  230.     }
  231.     strcat(profBuf, ".dprof");
  232.  
  233.     ps = _ProfList;
  234.     _ProfList = NULL;
  235.  
  236.     fh = Open(profBuf, 1006);
  237.  
  238.     ph.ph_NumIds  = _ProfId;
  239.     ph.ph_Magic   = PROF_MAGIC;
  240.     ph.ph_TimeBase= GetEClockBase(&ev1);
  241.     Write(fh, &ph, sizeof(ph));
  242.  
  243.     for (; ps; ps = ps->ps_Link) {
  244.     ProfSym *psx;
  245.  
  246.     for (ps2 = ps; ps2; ps2 = psx) {
  247.         psx = ps2->ps_SibLink;
  248.  
  249.         ps2->ps_SibLink = NULL;
  250.         if (ps2->ps_Parent)
  251.         ps2->ps_Parent = (void *)ps2->ps_Parent->ps_Id;
  252.         if (fh) {
  253.         if (Write(fh, ps2, ps2->ps_Size) != ps2->ps_Size) {
  254.             Close(fh);
  255.             fh = 0;
  256.         }
  257.         }
  258.         ps2->ps_Parent = NULL;
  259.  
  260.         if (ps2 != ps)
  261.         FreeMem(ps2, ps2->ps_Size);
  262.     }
  263.     }
  264.     if (_ProfIot.tr_node.io_Device) {
  265.     CloseDevice(&_ProfIot.tr_node);
  266.     _ProfIot.tr_node.io_Device = NULL;
  267.     }
  268.     if (fh)
  269.     Close(fh);
  270. }
  271.  
  272. /*
  273.  *  Under 1.3 we have to use GetSysTime(), which is only accurate to
  274.  *  the vertical blank (about 1/60 second).  To reduce calculations and
  275.  *  allow for roll-over, however, we use microsecond timing with shifts.
  276.  *
  277.  *  This will glitch every 65536 seconds.
  278.  */
  279.  
  280. __regargs __noprof void
  281. ReadClock13(ev)
  282. struct EClockVal *ev;
  283. {
  284.     if (_ProfIot.tr_node.io_Device == NULL) {
  285.     OpenDevice("timer.device", UNIT_MICROHZ, &_ProfIot.tr_node, 0);
  286.     _ProfIot.tr_node.io_Command = TR_GETSYSTIME;
  287.     }
  288.     DoIO(&_ProfIot.tr_node);
  289.     ev->ev_lo = (unsigned short)_ProfIot.tr_time.tv_secs * (unsigned short)62500 + (_ProfIot.tr_time.tv_micro >> 4);
  290. }
  291.  
  292.  
  293.